﻿Imports System.Drawing.Drawing2D
Imports System.Text.RegularExpressions

Public Class FrmAjusterImage
    Private ImagePosition As New PointF(20, 20)
    Private ImageWScale As Single
    Private ImageHScale As Single
    Private ImageRatio As Single
    Private ImageRotation As Single
    Private gradient As New Bitmap(1, 1)
    Private CompositeImage As New Bitmap(1, 1)
    Private Image As New Bitmap(1, 1)
    Private ScaledImage As New Bitmap(1, 1)
    Private RotatedImage As New Bitmap(1, 1)
    Private Dragging As Boolean = False
    Private MouseOver As Boolean = False
    Private ScaleRatio As Boolean = True
    Private LastPos As New Point()
    Private _FinalSize As New Size(200, 250)
    Public Property FinalSize() As Size
        Get
            Return _FinalSize
        End Get
        Set(ByVal value As Size)
            _FinalSize = value
        End Set
    End Property

    Private _StartImage As Bitmap
    Public Property StartImage() As Bitmap
        Get
            Return _StartImage
        End Get
        Set(ByVal value As Bitmap)
            _StartImage = value
        End Set
    End Property

    Private _ResultImage As Bitmap
    Public ReadOnly Property ResultImage() As Bitmap
        Get
            Return _ResultImage
        End Get

    End Property

    Private Sub FrmAjusterImage_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        CompositeImage = New Bitmap(Pb_Render.Width, Pb_Render.Height)
        If Not StartImage Is Nothing Then
            Image = StartImage
            Dim oldW As Integer = RotatedImage.Width
            Dim oldH As Integer = RotatedImage.Height
            AutoScaleImage()
            RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
            ImagePosition = New PointF(ImagePosition.X - (RotatedImage.Width / 2 - oldW / 2), ImagePosition.Y - (RotatedImage.Height / 2 - oldH / 2))
        End If
        'Image = My.Resources.carpe_diem_logo
        'AutoScaleImage()
        'RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
        'ImagePosition = New Point(PictureBox1.Width / 2 - RotatedImage.Width / 2, PictureBox1.Height / 2 - RotatedImage.Height / 2)
        gradient = New Bitmap(CompositeImage.Width, CompositeImage.Height)
        Using g As Graphics = Graphics.FromImage(gradient)
            g.SmoothingMode = SmoothingMode.HighQuality
            g.CompositingQuality = CompositingQuality.HighQuality
            g.InterpolationMode = InterpolationMode.HighQualityBicubic
            Using gradBrush As New LinearGradientBrush(New Point(0, 0), New Point(0, CompositeImage.Height), Color.FromArgb(255, 150, 150, 150), Color.FromArgb(255, 40, 40, 40))
                g.FillRectangle(gradBrush, 0, 0, CompositeImage.Width, CompositeImage.Height)
            End Using
        End Using
        gradient = DitherImage(gradient)
        Dessiner()

    End Sub

    Private Sub Dessiner(Optional ByVal imageOnly As Boolean = False)
        Dim ImageBound As New RectangleF(CType(CompositeImage.Width, Single) / 2 - CType(FinalSize.Width, Single) / 2, _
                           CType(CompositeImage.Height, Single) / 2 - CType(FinalSize.Height, Single) / 2, _
                           CType(FinalSize.Width, Single), CType(FinalSize.Height, Single))
        If imageOnly Then
            CompositeImage = New Bitmap(CompositeImage.Width, CompositeImage.Height)
        End If
        Using g As Graphics = Graphics.FromImage(CompositeImage)
            'g.Clear(Color.fromArgb(98,98,98))
            'g.Clear(Color.FromArgb(50, 50, 50))
            g.SmoothingMode = SmoothingMode.HighQuality
            g.CompositingQuality = CompositingQuality.HighQuality
            g.InterpolationMode = InterpolationMode.HighQualityBicubic
            If Not imageOnly Then
                g.DrawImage(gradient, 0, 0)
            End If

            'g.DrawRectangle(Pens.Gray, 0, 0, CompositeImage.Width - 1, CompositeImage.Height - 1)
            g.DrawImage(RotatedImage, ImagePosition)

            Dim ext As New Region(New Rectangle(0, 0, CompositeImage.Width, CompositeImage.Height))
            ext.Exclude(ImageBound)
            g.FillRegion(New SolidBrush(Color.FromArgb(150, 0, 0, 0)), ext)
            If Not imageOnly Then
                g.DrawRectangle(Pens.White, ImageBound.X - 1, ImageBound.Y - 1, ImageBound.Width + 2, ImageBound.Height + 2)
                g.DrawRectangle(Pens.Black, ImageBound.X - 2, ImageBound.Y - 2, ImageBound.Width + 4, ImageBound.Height + 4)
            End If

        End Using
        Using g As Graphics = Pb_Render.CreateGraphics()
            g.DrawImage(CompositeImage, 0, 0)

        End Using
    End Sub

    Public Function RotateImageByAngle(bmp As Bitmap, angle As Single) As Bitmap
        'Create new empty BitMap with the original images dimensions
        Dim radius As Single = Math.Ceiling(Math.Sqrt(Math.Pow(bmp.Width / 2, 2) + Math.Pow(bmp.Height / 2, 2)))
        Dim img As New Bitmap(CType(radius * 2, Integer), CType(radius * 2, Integer))
        'Create a Graphics object from the BipMap with Graphics.FromFile
        Dim g As Graphics = Graphics.FromImage(img)
        g.SmoothingMode = SmoothingMode.AntiAlias
        g.InterpolationMode = InterpolationMode.HighQualityBicubic
        g.CompositingQuality = CompositingQuality.HighQuality

        'Move the rotation point to the center of the image
        g.TranslateTransform(CType(img.Width, Single) / 2, CType(img.Height, Single) / 2)
        'Now rotate the image
        g.RotateTransform(angle)
        'Move the rotation point back to the center of the image
        g.TranslateTransform(-CType(img.Width, Single) / 2, -CType(img.Height, Single) / 2)
        'Now we draw (Grahics.Draw) to get the newly rotated image onto the blank Bitmap
        g.DrawImage(bmp, New PointF(radius - CType(bmp.Width, Single) / 2, radius - CType(bmp.Height, Single) / 2))
        'g.DrawEllipse(Pens.Red, New RectangleF(0, 0, radius * 2, radius * 2))
        'g.DrawLine(Pens.Red, 0, radius, radius * 2, radius)
        'g.DrawLine(Pens.Red, radius, 0, radius, radius * 2)
        'Return the rotated image
        Return img
    End Function


    Private Sub PictureBox1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Pb_Render.Paint
        e.Graphics.DrawImage(CompositeImage, 0, 0)
    End Sub

    Private Sub PictureBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_Render.MouseDown
        LastPos = e.Location
        Dragging = True
    End Sub

    Private Sub PictureBox1_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_Render.MouseUp
        Dragging = False
    End Sub

    Private Function DitherImage(ByVal img As Bitmap) As Bitmap
        Dim nimg As New Bitmap(img.Width, img.Height)
        For x = 0 To img.Width - 1
            For y = 0 To img.Height - 1
                If y Mod 2 = 0 Then
                    If y + 3 < img.Height AndAlso x Mod 2 = 0 Then
                        nimg.SetPixel(x, y, img.GetPixel(x, y + 3))
                    Else
                        nimg.SetPixel(x, y, img.GetPixel(x, y))
                    End If
                Else
                    If y + 3 < img.Height AndAlso x Mod 2 = 1 Then
                        nimg.SetPixel(x, y, img.GetPixel(x, y + 3))
                    Else
                        nimg.SetPixel(x, y, img.GetPixel(x, y))
                    End If
                End If
            Next
        Next
        Return nimg
    End Function

    Private Sub PictureBox1_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_Render.MouseMove
        If Dragging Then
            ImagePosition = New Point(ImagePosition.X + e.X - LastPos.X, ImagePosition.Y + e.Y - LastPos.Y)
            LastPos = e.Location
            Dessiner()
        End If

    End Sub

    Private Sub Form1_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
        If MouseOver AndAlso Pb_Render.Focused Then
            If e.Delta > 0 Then
                ImageRotation += 2.5F
            Else
                ImageRotation -= 2.5F
            End If
            Tb_Rotation.Text = ImageRotation.ToString("0.0")
            RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
            Dessiner()
            'Cursor = Cursors.WaitCursor
        End If

    End Sub

    Private Sub Tb_Scale_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Tb_WScale.MouseWheel, TB_HScale.MouseWheel
        If sender.Equals(Tb_WScale) Or ScaleRatio Then
            If e.Delta > 0 Then
                ImageWScale += 1
            Else
                ImageWScale -= 1
            End If
        End If

        If sender.Equals(TB_HScale) Or ScaleRatio Then
            If e.Delta > 0 Then
                ImageHScale += 1
            Else
                ImageHScale -= 1
            End If
        End If
        ImageWScale = Math.Max(ImageWScale, 0.1F)
        ImageHScale = Math.Max(ImageHScale, 0.1F)
        
        ScaleImage()
        
        Dessiner()
    End Sub

    Private Sub Tb_Rotation_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Tb_Rotation.MouseWheel
        If e.Delta > 0 Then
            ImageRotation += 1
        Else
            ImageRotation -= 1
        End If
        Tb_Rotation.Text = ImageRotation.ToString("0.0")
        RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
        Dessiner()
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Btn_ChoisirImage.Click
        Using diag As New OpenFileDialog
            diag.Filter = "Image Files|*.png;*.bmp;*.jpg|All Files|*.*"
            If diag.ShowDialog() = DialogResult.OK Then
                Try
                    Image = New Bitmap(diag.FileName)
                Catch ex As Exception
                    MessageBox.Show("Type de fichier inconnu ou fichier corompu.", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    Return
                End Try

                ImageRotation = 0
                Tb_Rotation.Text = ImageRotation.ToString("0.0")
                AutoScaleImage()
                RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
                ImagePosition = New PointF(Pb_Render.Width / 2 - RotatedImage.Width / 2, Pb_Render.Height / 2 - RotatedImage.Height / 2)
                Dessiner()
            End If
        End Using
    End Sub

    Private Sub AutoScaleImage()
        Dim width, height As Integer
        Dim ContentBound As New Rectangle(20, 20, Pb_Render.Width - 40, Pb_Render.Height - 40)
        If Image.Width / Image.Height > ContentBound.Width / ContentBound.Height Then
            ImageRatio = Math.Min(ContentBound.Width, Image.Width) / Image.Width
            width = Math.Min(ContentBound.Width, Image.Width)
            height = Math.Round(Image.Height * ImageRatio)
        Else
            ImageRatio = Math.Min(ContentBound.Height, Image.Height) / Image.Height
            width = Math.Round(Image.Width * ImageRatio)
            height = Math.Min(ContentBound.Height, Image.Height)
        End If
        ImageWScale = (100 * width) / Image.Width
        ImageHScale = (100 * height) / Image.Height
        Tb_WScale.Text = ImageWScale.ToString("0.00") + "%"
        TB_HScale.Text = ImageHScale.ToString("0.00") + "%"
        Console.WriteLine("scale = " + ImageWScale.ToString)
        ScaledImage = New Bitmap(width, height)
        Using g As Graphics = Graphics.FromImage(ScaledImage)
            g.SmoothingMode = SmoothingMode.HighQuality
            g.InterpolationMode = InterpolationMode.HighQualityBicubic
            g.PixelOffsetMode = PixelOffsetMode.HighQuality
            g.DrawImage(Image, New Rectangle(0, 0, width, height))
        End Using
    End Sub
    Private Sub ScaleImage()
        Dim oldW As Integer = RotatedImage.Width
        Dim oldH As Integer = RotatedImage.Height
        Dim width, height As Integer
        width = CType(Image.Width, Single) / 100 * ImageWScale
        height = CType(Image.Height, Single) / 100 * ImageHScale
        ScaledImage = New Bitmap(Math.Max(width, 1), Math.Max(height, 1))
        Using g As Graphics = Graphics.FromImage(ScaledImage)
            g.SmoothingMode = SmoothingMode.HighQuality
            g.InterpolationMode = InterpolationMode.HighQualityBicubic
            g.PixelOffsetMode = PixelOffsetMode.HighQuality
            g.DrawImage(Image, New Rectangle(0, 0, width, height))
        End Using
        RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
        ImagePosition = New PointF(ImagePosition.X - (RotatedImage.Width / 2 - oldW / 2), ImagePosition.Y - (RotatedImage.Height / 2 - oldH / 2))
        Tb_WScale.Text = ImageWScale.ToString("0.00") + "%"
        TB_HScale.Text = ImageHScale.ToString("0.00") + "%"
    End Sub

    Private Sub PictureBox1_Resize(sender As System.Object, e As System.EventArgs) Handles Pb_Render.Resize
        CompositeImage = New Bitmap(Pb_Render.Width, Pb_Render.Height)
        AutoScaleImage()
        RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
        ImagePosition = New Point(Pb_Render.Width / 2 - RotatedImage.Width / 2, Pb_Render.Height / 2 - RotatedImage.Height / 2)
        Dessiner()
    End Sub

    Private Sub Pb_Render_MouseEnter(sender As System.Object, e As System.EventArgs) Handles Pb_Render.MouseEnter
        MouseOver = True
    End Sub

    Private Sub Pb_Render_MouseLeave(sender As System.Object, e As System.EventArgs) Handles Pb_Render.MouseLeave
        MouseOver = False
    End Sub

    Private Sub Pb_Render_Click(sender As System.Object, e As System.EventArgs) Handles Pb_Render.Click
        Pb_Render.Focus()
        Pb_Render.Select()
    End Sub

    Private Sub Btn_ScaleRatio_Click(sender As System.Object, e As System.EventArgs) Handles Btn_ScaleRatio.Click
        ScaleRatio = Not ScaleRatio
        If ScaleRatio Then
            ImageHScale = (ImageHScale + ImageWScale) / 2
            ImageWScale = ImageHScale
            ScaleImage()
            Dessiner()
            Btn_ScaleRatio.BackColor = SystemColors.ControlLight
            Btn_ScaleRatio.FlatAppearance.BorderSize = 1
        Else
            Btn_ScaleRatio.BackColor = SystemColors.Control
            Btn_ScaleRatio.FlatAppearance.BorderSize = 0
        End If
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim ImageBound As New RectangleF(CType(CompositeImage.Width, Single) / 2 - CType(FinalSize.Width, Single) / 2, _
                            CType(CompositeImage.Height, Single) / 2 - CType(FinalSize.Height, Single) / 2, _
                            CType(FinalSize.Width, Single), CType(FinalSize.Height, Single))
        Dim finalImage As New Bitmap(FinalSize.Width, FinalSize.Height)
        Dim test As New Rectangle(CType(ImageBound.X, Integer), CType(ImageBound.Y, Integer), CType(ImageBound.Width, Integer), CType(ImageBound.Height, Integer))
        Console.WriteLine(FinalSize.ToString())
        Dessiner(True)
        Using g As Graphics = Graphics.FromImage(finalImage)
            g.SmoothingMode = SmoothingMode.HighQuality
            g.CompositingQuality = CompositingQuality.HighQuality
            g.InterpolationMode = InterpolationMode.HighQualityBicubic
            g.DrawImageUnscaledAndClipped(CompositeImage, New Rectangle(-test.X, -test.Y, FinalSize.Width + test.X, FinalSize.Height + test.Y))
        End Using
        _ResultImage = finalImage
        Me.DialogResult = Windows.Forms.DialogResult.OK
        'PictureBox1.BackgroundImage = finalImage
    End Sub

    Private Sub Tb_Scale_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles Tb_WScale.Validating, TB_HScale.Validating
        Dim reg As New Regex("^(\d+)*([.,]\d{1,4})*[\s]*[%]{0,1}$")
        If Not reg.IsMatch(CType(sender, TextBox).Text) Then
            Tb_WScale.Text = ImageWScale.ToString("0.00") + "%"
            TB_HScale.Text = ImageHScale.ToString("0.00") + "%"
            Return
        End If
        
        Dim nW, nH As Single
        nW = 0
        nH = 0
        If sender.Equals(Tb_WScale) Then
            Single.TryParse(Tb_WScale.Text.Replace(" ", "").Replace("%", ""), nW)
            If ScaleRatio Then
                nH = nW
            End If
        End If
        If sender.Equals(TB_HScale) Then
            Single.TryParse(TB_HScale.Text.Replace(" ", "").Replace("%", ""), nH)
            If ScaleRatio Then
                nW = nH
            End If
        End If

        ImageWScale = Math.Max(nW, 0.1F)
        ImageHScale = Math.Max(nH, 0.1F)

        ScaleImage()
        
        Dessiner()
    End Sub

    Private Sub Tb_Rotation_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles Tb_Rotation.Validating
        Dim reg As New Regex("^[-]{0,1}(\d+)*([.,]\d{1,4})*$")
        If Not reg.IsMatch(CType(sender, TextBox).Text) Then
            Tb_Rotation.Text = ImageRotation.ToString("0.0")
            Return
        End If
        Dim nR As Single
        nR = 0
        Single.TryParse(Tb_Rotation.Text, nR)
        ImageRotation = nR
        Tb_Rotation.Text = ImageRotation.ToString("0.0")
        RotatedImage = RotateImageByAngle(ScaledImage, ImageRotation)
        Dessiner()
    End Sub

    Private Sub TableLayoutPanel1_Click(sender As System.Object, e As System.EventArgs) Handles TableLayoutPanel1.Click
        TableLayoutPanel1.Focus()
    End Sub

    Private Sub Gb_Trans_Click(sender As System.Object, e As System.EventArgs) Handles Gb_Trans.Click
        Gb_Trans.Focus()
    End Sub
End Class